﻿using System;
using System.Linq;
using System.Reflection;
using Common.Attributes;
using Common.Enums;
using Common.Filter;
using Common.Helper;
using Common.Interceptors;
using Common.Job;
using DotXxlJob.Core;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.AspNetCore.Hosting;
using Snowflake.Net;

namespace Common.Extensions
{
    /// <summary>
    /// 依赖注入
    /// </summary>
    public static class DependencyInjectionExtersion
    {
        private static readonly ILoggerFactory LoggerFactory = Microsoft.Extensions.Logging.LoggerFactory.Create(
            builder =>
            {
#if DEBUG
                builder.AddConsole();
#endif
            });


        /// <summary>
        /// 添加AddDbContextPool
        /// </summary>
        /// <returns></returns>
        public static IServiceCollection AddDbContextPool<TContext>(this IServiceCollection services,
            IConfiguration configurationSection) where TContext : DbContext
        {
            IdWorkerHelper.Initialize(configurationSection);

            // var workerId = configurationSection.GetValue<long>("Snowflake:WorkerId");
            // var datacenterId = configurationSection.GetValue<long>("Snowflake:DatacenterId");
            // services.AddSingleton(new IdWorker(workerId, datacenterId));

            // services.AddDbContext<TContext>((serviceProvider, options) =>
            //     {
            //         options.UseMySql(configurationSection["ConnectionDb"],
            //             new MySqlServerVersion(new Version(5, 7, 21)));
            //         //options.UseLazyLoadingProxies();
            //         // options.UseLoggerFactory(LoggerFactory);
            //         options.AddInterceptors(serviceProvider.GetRequiredService<SqlLoggingInterceptor>());
            //     }
            // );

            services.AddDbContextPool<TContext>((serviceProvider, options) =>
                {
                    options.UseMySql(configurationSection["ConnectionDb"],
                        new MySqlServerVersion(new Version(5, 7, 21)));
                    //options.UseLazyLoadingProxies();
                    // options.UseLoggerFactory(LoggerFactory);
                    options.AddInterceptors(serviceProvider.GetRequiredService<SqlLoggingInterceptor>());
                },
                200
            );

            return services;
        }

        /// <summary>
        /// 添加注入
        /// </summary>
        /// <returns></returns>
        public static IServiceCollection AddService(this IServiceCollection services,
            IConfiguration configurationSection)
        {
            var assemblys = configurationSection.GetSection("Assemblys");
            if (assemblys == null) throw new Exception("请配置appsettings文件中Assemblys节点");

            foreach (var section in assemblys.GetChildren()) RegisterComponentClass(services, section);

            //注入IHttpContextAccessor，获取httpContext
            services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
            services.AddSingleton<SqlLoggingInterceptor>();
            services.AddScoped<TokenAuthenticationFilter>();

            return services;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="services"></param>
        /// <param name="section"></param>
        private static void RegisterComponentClass(IServiceCollection services, IConfigurationSection section)
        {
            var assembly = Assembly.Load(section.Value);
            foreach (var type in assembly.GetTypes())
            {
                var attribute = type.GetCustomAttribute<ComponentAttribute>();
                if (attribute == null) continue;

                var serviceType = attribute.ServiceType;
                //情况1 适用于依赖抽象编程，注意这里只获取第一个
                if (serviceType == null && attribute.InterfaceServiceType)
                    serviceType = type.GetInterfaces().FirstOrDefault();

                switch (attribute.Lifetime)
                {
                    case LifeTime.Singleton:
                        services.AddSingleton(serviceType, type);
                        break;
                    case LifeTime.Scoped:
                        services.AddScoped(serviceType, type);
                        break;
                    case LifeTime.Transient:
                        services.AddTransient(serviceType, type);
                        break;
                    default:
                        services.AddTransient(serviceType, type);
                        break;
                }

                // LoggerFactory.CreateLogger("DependencyInjectionService")
                //     .LogInformation($"注入Bean: {serviceType} {type} {attribute.Lifetime}");
                Console.WriteLine($"注入Bean: {serviceType} {type} {attribute.Lifetime}");
            }
        }

        /// <summary>
        /// 添加xxl-job
        /// </summary>
        /// <param name="services"></param>
        /// <param name="configurationSection"></param>
        /// <returns></returns>
        public static IServiceCollection AddxxlJobs(this IServiceCollection services,
            IConfiguration configurationSection)
        {
            var enable = !string.IsNullOrEmpty(configurationSection["XxlJob:enable"]) && Convert.ToBoolean(configurationSection["XxlJob:enable"]);
            if (!enable) return services;
            services.AddXxlJobExecutor(configurationSection);
            services.AddAutoRegistry();
            return services;
        }

        public static IApplicationBuilder UseXxlJobExecutor(this IApplicationBuilder builder, IConfiguration configurationSection)
        {
            var enable = !string.IsNullOrEmpty(configurationSection["XxlJob:enable"]) && Convert.ToBoolean(configurationSection["XxlJob:enable"]);
            if (!enable) return builder;
            return builder.UseMiddleware<XxlJobExecutorMiddleware>();
        }
    }
}